import { DesignTable } from '@amcax/base';
import { LinkOutlined } from '@ant-design/icons';
import { DraggableModal } from '@app-base/common/components/draggable-modal/DraggableModal';
import { MessageTip } from '@app-cad/common/utils/MessageTip';
import { ctx2 } from '@app-cad/module';
import { Button, Col, Row, Space } from 'antd';
import { FC, KeyboardEvent, useEffect, useMemo, useRef, useState } from 'react';
import { Cell, Column, HeaderCell, Table } from 'rsuite-table';

import './DesignTableEditor.scss';

interface DesignTableEditorProps {
  open: boolean;
  tableId: string;
  table: DesignTable | undefined;
  setOpen: (open: boolean) => void;
  parameterId?: string;
  setParameter?: (value: number) => void;
}

export const DesignTableEditor: FC<DesignTableEditorProps> = ({
  open,
  tableId,
  table,
  setOpen,
  parameterId,
  setParameter,
}) => {
  const {
    commandCenters: { designTableCommands },
    docMgr,
  } = ctx2;
  const [editValues, setEditValues] = useState<number[][]>([]);
  const [editLabels, setEditLabels] = useState<string[]>([]);

  const [selectedCol, setSelectedCol] = useState<number>();
  const [selectedRow, setSelectedRow] = useState<number>();

  const parameterCoordinates = useMemo(
    () =>
      table && parameterId && table.active && table.configuration >= 0
        ? {
            row: table.configuration,
            col: table.keys.indexOf(parameterId),
          }
        : null,
    [table, parameterId],
  );

  const [loading, setLoading] = useState(false);

  const [editingHeaderCol, setEditingHeaderCol] = useState<number | null>(null);

  const [editingCell, setEditingCell] = useState<{
    row: number;
    col: number;
  } | null>(null);

  const tableRef = useRef<any>(null);

  useEffect(() => {
    if (table) {
      setSelectedRow(undefined);
      setSelectedCol(undefined);

      const rowCount = table.values.length / table.labels.length;
      const values2d: number[][] = [];
      for (let i = 0; i < rowCount; i++) {
        values2d.push(
          table.values.slice(
            i * table.labels.length,
            (i + 1) * table.labels.length,
          ),
        );
      }
      setEditValues(values2d);
      setEditLabels([...table.labels]);
    }
  }, [table, open]);

  useEffect(() => {
    setEditingCell(parameterCoordinates);
  }, [parameterCoordinates]);

  const lockedCols = (table?.keys || []).map((k) => !!k);
  const hasLockedCol = lockedCols.some(Boolean);

  const handleRowClick = ({ rowIdx }) => {
    if (!parameterCoordinates) {
      setSelectedRow(rowIdx === table.configuration ? undefined : rowIdx);
      setSelectedCol(undefined);
    }
  };

  const handleColHeaderClick = (colIdx: number) => {
    if (!parameterCoordinates) {
      setSelectedCol(lockedCols[colIdx] ? undefined : colIdx);
      setSelectedRow(undefined);
    }
  };

  const getScrollPosition = () => ({
    left: tableRef.current?.scrollPosition?.left ?? 0,
    top: tableRef.current?.scrollPosition?.top ?? 0,
  });

  const restoreScrollPositionDuring = (
    pos: { left: number; top: number },
    ms = 300,
  ) => {
    setTimeout(() => {
      tableRef.current?.scrollLeft(pos.left);
      tableRef.current?.scrollTop(pos.top);
    }, ms);
  };

  const handleAddRow = async () => {
    await updateTableValues([...editValues, Array(editLabels.length).fill(0)], {
      left: 0,
      top: 99999,
    });
  };

  function getNextColLabel(labels: string[]): string {
    let idx = 1;
    while (labels.includes(`参数.${idx}`)) {
      idx++;
    }
    return `参数.${idx}`;
  }

  const handleAddCol = async () => {
    const newLabel = getNextColLabel(editLabels);
    try {
      await designTableCommands.addDesignTableCol(tableId, [newLabel]);
      await docMgr.updateDocumentObjects();

      restoreScrollPositionDuring({ left: 99999, top: 0 });
    } catch (err: any) {
      MessageTip.error(err?.message || '增加列失败');
    }
  };

  async function updateTableValues(
    newValues: number[][],
    posAfterUpdate?: { left: number; top: number },
  ) {
    setLoading(true);
    const prevScroll = getScrollPosition();

    try {
      const flatValues = newValues.flat();
      await designTableCommands.EditDesignTable(tableId, flatValues);
    } catch (err: any) {
      MessageTip.error(err?.message || '设计表编辑命令执行失败');
    } finally {
      restoreScrollPositionDuring(posAfterUpdate || prevScroll);
      setLoading(false);
    }

    await docMgr.updateDocumentObjects();
  }

  const handleDelete = async () => {
    const prevScroll = getScrollPosition();

    if (selectedCol !== undefined) {
      await designTableCommands.deleteDesignTableCol(tableId, selectedCol);
      await docMgr.updateDocumentObjects();
      setSelectedCol(undefined);
    } else if (selectedRow !== undefined) {
      await designTableCommands.deleteDesignTableRow(tableId, selectedRow);
      await docMgr.updateDocumentObjects();
      setSelectedRow(undefined);
    }

    restoreScrollPositionDuring(prevScroll);
  };

  const closeEditor = () => {
    setOpen(false);
  };

  const onInputKeyDown = (e: KeyboardEvent<HTMLInputElement>) => {
    if (e.key === 'Enter') {
      e.stopPropagation();
      (e.target as HTMLInputElement).blur();
    }
  };

  return (
    <DraggableModal
      open={open}
      onCancel={closeEditor}
      title='编辑设计表'
      footer={null}
      width={800}
      maskClosable={false}
    >
      <div> 说明：双击列标题可以编辑列名，双击单元格可以编辑单元格内容。</div>
      {(hasLockedCol || (table && table.configuration >= 0)) && (
        <div className='text-[#fda414] mb-0'>
          {hasLockedCol &&
            '已与模型参数建立关联映射关系的参数列被锁定，名称不允许修改、列不允许删除；需解除关联后再编辑。'}
          {table &&
            table.configuration >= 0 &&
            '当前模型中使用的配置行（粗体、序号旁带星号的数据行）无法删除。'}
        </div>
      )}
      <Table
        ref={tableRef}
        className='design-table-editor-grid'
        data={editValues.map((row, rowIdx) => ({ ...row, rowIdx }))}
        height={300}
        rowHeight={36}
        headerHeight={36}
        bordered
        cellBordered
        rowClassName={(_rowData, rowIndex) =>
          selectedRow === rowIndex
            ? 'selected-row'
            : rowIndex === table.configuration
              ? 'used-configuration-row'
              : ''
        }
        onRowClick={handleRowClick}
      >
        <Column
          width={60}
          align='center'
          fixed
        >
          <HeaderCell>序号</HeaderCell>
          <Cell>
            {(_, rowIndex: number) =>
              rowIndex === table.configuration ? (
                <>{rowIndex + 1} *</>
              ) : (
                rowIndex + 1
              )
            }
          </Cell>
        </Column>

        {editLabels.map((_, colIdx) => (
          <Column
            key={colIdx}
            width={120}
            align='center'
            resizable
          >
            <HeaderCell
              style={{
                cursor: lockedCols[colIdx] ? 'default' : 'pointer',
                background: selectedCol === colIdx ? '#f3f2ff' : undefined,
                borderTop:
                  selectedCol === colIdx ? '4px solid #464681' : undefined,
                borderBottom:
                  selectedCol === colIdx ? '1px solid #464681' : undefined,
              }}
            >
              {editingHeaderCol === colIdx && !lockedCols[colIdx] ? (
                <input
                  autoFocus
                  style={{
                    width: '100%',
                    border: 'none',
                    background: '#fff',
                    textAlign: 'center',
                  }}
                  defaultValue={editLabels[colIdx]}
                  onBlur={async (e) => {
                    setEditingHeaderCol(null);
                    const newValue = e.target.value;
                    if (
                      editLabels.some(
                        (label, idx) => idx !== colIdx && label === newValue,
                      )
                    ) {
                      MessageTip.error('列标题不能重名');
                      return;
                    }
                    if (newValue !== editLabels[colIdx]) {
                      const prevScroll = getScrollPosition();

                      try {
                        await designTableCommands.editDesignTableColName(
                          tableId,
                          colIdx,
                          newValue,
                        );
                        const newLabels = [...editLabels];
                        newLabels[colIdx] = newValue;
                        setEditLabels(newLabels);
                      } catch (err: any) {
                        MessageTip.error(err?.message || '列名修改失败');
                      }
                      restoreScrollPositionDuring(prevScroll);
                    }
                  }}
                  onKeyDown={onInputKeyDown}
                />
              ) : (
                <div
                  className='w-full text-center outline-none'
                  onClick={() => {
                    handleColHeaderClick(colIdx);
                  }}
                  onDoubleClick={() => {
                    if (!parameterCoordinates && !lockedCols[colIdx]) {
                      setEditingHeaderCol(colIdx);
                    }
                  }}
                >
                  {editLabels[colIdx]}
                  {lockedCols[colIdx] && (
                    <Space>
                      <LinkOutlined className='text-[#fda414]' />
                    </Space>
                  )}
                </div>
              )}
            </HeaderCell>
            <Cell
              style={{
                background: selectedCol === colIdx ? '#f3f2ff' : undefined,
              }}
            >
              {(_, rowIndex: number) => {
                const isEditing =
                  editingCell &&
                  editingCell.row === rowIndex &&
                  editingCell.col === colIdx;

                return isEditing ? (
                  <input
                    ref={(el) => {
                      if (
                        el &&
                        el === document.activeElement &&
                        el.selectionStart === 0 &&
                        el.selectionEnd === el.value.length
                      ) {
                        return;
                      }
                      if (el && !el.dataset.selected) {
                        el.focus();
                        el.select();
                        el.dataset.selected = 'true';
                      }
                    }}
                    className='w-full bg-white border-2'
                    defaultValue={
                      editValues[rowIndex] &&
                      editValues[rowIndex][colIdx] !== undefined
                        ? editValues[rowIndex][colIdx]
                        : ''
                    }
                    onBlur={async (e) => {
                      const newValues = editValues.map((arr) => [...arr]);
                      const value = e.target.value;
                      newValues[rowIndex][colIdx] =
                        value.trim() === ''
                          ? 0
                          : isNaN(Number(value))
                            ? 0
                            : Number(value);

                      if (parameterCoordinates) {
                        if (
                          parameterCoordinates.row === rowIndex &&
                          parameterCoordinates.col === colIdx
                        ) {
                          if (
                            editValues[rowIndex][colIdx] ===
                            newValues[rowIndex][colIdx]
                          ) {
                            return;
                          }

                          setParameter(newValues[rowIndex][colIdx]);
                        }
                      }

                      setEditValues(newValues);
                      setEditingCell(null);

                      await updateTableValues(newValues);
                    }}
                    onKeyDown={onInputKeyDown}
                  />
                ) : (
                  <div
                    className='w-full text-center outline-none'
                    onDoubleClick={() => {
                      if (!parameterCoordinates) {
                        setEditingCell({ row: rowIndex, col: colIdx });
                      }
                    }}
                  >
                    {editValues[rowIndex]?.[colIdx] || null}
                  </div>
                );
              }}
            </Cell>
          </Column>
        ))}
      </Table>
      <Row
        justify='space-between'
        className='mt-4'
      >
        <Col>
          {!parameterCoordinates && (
            <>
              <Button
                disabled={editLabels.length === 0}
                onClick={handleAddRow}
              >
                增加一行
              </Button>
              <Button onClick={handleAddCol}>增加一列</Button>
              <Button
                disabled={
                  (selectedCol === undefined && selectedRow === undefined) ||
                  loading
                }
                onClick={handleDelete}
                style={{ marginLeft: 8 }}
              >
                删除
              </Button>
            </>
          )}
        </Col>
        <Col>
          <Button
            onClick={closeEditor}
            style={{ marginRight: 8 }}
          >
            关闭
          </Button>
        </Col>
      </Row>
    </DraggableModal>
  );
};
